import hashlib
import uuid
import secrets
from datetime import datetime
from typing import Any, Dict, List, Optional
import json


class CommonUtils:
    """通用工具类"""

    @staticmethod
    def generate_uuid() -> str:
        """生成UUID"""
        return str(uuid.uuid4())

    @staticmethod
    def generate_short_id(length: int = 8) -> str:
        """生成短ID"""
        return secrets.token_urlsafe(length)[:length]

    @staticmethod
    def generate_random_string(length: int = 16) -> str:
        """生成随机字符串"""
        return secrets.token_urlsafe(length)

    @staticmethod
    def calculate_md5(content: str) -> str:
        """计算MD5哈希值"""
        return hashlib.md5(content.encode('utf-8')).hexdigest()

    @staticmethod
    def calculate_file_md5(file_path: str) -> str:
        """计算文件MD5哈希值"""
        hash_md5 = hashlib.md5()
        with open(file_path, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                hash_md5.update(chunk)
        return hash_md5.hexdigest()

    @staticmethod
    def format_datetime(dt: datetime, format_str: str = "%Y-%m-%d %H:%M:%S") -> str:
        """格式化日期时间"""
        if dt is None:
            return ""
        return dt.strftime(format_str)

    @staticmethod
    def parse_datetime(dt_str: str, format_str: str = "%Y-%m-%d %H:%M:%S") -> Optional[datetime]:
        """解析日期时间字符串"""
        try:
            return datetime.strptime(dt_str, format_str)
        except (ValueError, TypeError):
            return None

    @staticmethod
    def format_file_size(size_bytes: int) -> str:
        """格式化文件大小"""
        if size_bytes == 0:
            return "0B"

        size_names = ["B", "KB", "MB", "GB", "TB"]
        i = 0
        while size_bytes >= 1024.0 and i < len(size_names) - 1:
            size_bytes /= 1024.0
            i += 1

        return f"{size_bytes:.1f}{size_names[i]}"

    @staticmethod
    def safe_json_loads(json_str: str, default: Any = None) -> Any:
        """安全的JSON解析"""
        try:
            return json.loads(json_str)
        except (json.JSONDecodeError, TypeError):
            return default

    @staticmethod
    def safe_json_dumps(obj: Any, default: str = "{}") -> str:
        """安全的JSON序列化"""
        try:
            return json.dumps(obj, ensure_ascii=False, separators=(',', ':'))
        except (TypeError, ValueError):
            return default

    @staticmethod
    def dict_to_tree(items: List[Dict], id_key: str = 'id', parent_key: str = 'parent_id', children_key: str = 'children') -> List[Dict]:
        """将扁平字典列表转换为树形结构"""
        # 创建索引映射
        item_map = {item[id_key]: item for item in items}
        tree = []

        for item in items:
            parent_id = item.get(parent_key)
            if parent_id is None or parent_id == 0 or parent_id not in item_map:
                # 根节点
                tree.append(item)
            else:
                # 子节点
                parent = item_map[parent_id]
                if children_key not in parent:
                    parent[children_key] = []
                parent[children_key].append(item)

        return tree

    @staticmethod
    def flatten_tree(tree: List[Dict], children_key: str = 'children') -> List[Dict]:
        """将树形结构扁平化"""
        result = []

        def traverse(nodes):
            for node in nodes:
                children = node.pop(children_key, [])
                result.append(node)
                if children:
                    traverse(children)

        traverse(tree)
        return result

    @staticmethod
    def mask_sensitive_info(text: str, mask_char: str = '*', start: int = 3, end: int = 4) -> str:
        """掩码敏感信息"""
        if not text or len(text) <= start + end:
            return text

        return text[:start] + mask_char * (len(text) - start - end) + text[-end:]

    @staticmethod
    def get_client_ip(request) -> str:
        """获取客户端IP地址"""
        # 尝试从各种头部获取真实IP
        headers_to_check = [
            'X-Forwarded-For',
            'X-Real-IP',
            'X-Forwarded-Proto',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_REAL_IP',
        ]

        for header in headers_to_check:
            ip = request.headers.get(header)
            if ip:
                # X-Forwarded-For可能包含多个IP，取第一个
                return ip.split(',')[0].strip()

        # 如果没有找到，返回客户端地址
        return request.client.host if request.client else "unknown"

    @staticmethod
    def parse_user_agent(user_agent: str) -> Dict[str, str]:
        """解析User-Agent"""
        # 这里可以使用user-agents库进行更详细的解析
        # 这里提供简单的解析示例
        browser = "Unknown"
        os = "Unknown"

        if "Chrome" in user_agent:
            browser = "Chrome"
        elif "Firefox" in user_agent:
            browser = "Firefox"
        elif "Safari" in user_agent:
            browser = "Safari"
        elif "Edge" in user_agent:
            browser = "Edge"

        if "Windows" in user_agent:
            os = "Windows"
        elif "Mac" in user_agent:
            os = "macOS"
        elif "Linux" in user_agent:
            os = "Linux"
        elif "Android" in user_agent:
            os = "Android"
        elif "iOS" in user_agent:
            os = "iOS"

        return {
            "browser": browser,
            "os": os,
            "full": user_agent
        }